package dom.xpath.util;

/**
 * This class contains methods for performance measurements.
 *
 * @author Workgroup DBIS, University of Konstanz 2005-07, ISC License
 * @author Christian Gruen
 */
public final class Performance {
  /** Performance Timer, based on nano seconds. */
  private long time;

  /**
   * Constructor, initializing the performance timer.
   */
  public Performance() {
    initTimer();
  }

  /**
   * Initializes the timer.
   */
  public void initTimer() {
    time = System.nanoTime();
  }

  /**
   * Returns the measured execution time in nanoseconds.
   * @return execution time
   */
  public long getTime() {
    final long time2 = System.nanoTime();
    final long diff = time2 - time;
    time = time2;
    return diff;
  }

  /**
   * Returns the measured execution time in milliseconds and reinitializes
   * the timer.
   * @return execution time
   */
  public String getTimer() {
    return getTimer(1);
  }

  /**
   * Returns the measured execution time in milliseconds, divided by the
   * number of runs, and reinitializes the timer.
   * @param runs number of runs
   * @return execution time
   */
  public String getTimer(final int runs) {
    final long time2 = System.nanoTime();
    final String t = getTimer(time2 - time, runs);
    time = time2;
    return t;
  }

  /**
   * Returns a string with the measured execution time in milliseconds.
   * @param time measured time in nanoseconds
   * @param runs number of runs
   * @return execution time
   */
  public static String getTimer(final long time, final int runs) {
    return (time / runs / 10000) / 100.0 + " ms" + (runs > 1 ? " (avg)" : "");
  }

  /**
   * Returns a formatted representation of the current memory consumption.
   * @return memory consumption
   */
  public static String getMem() {
    final Runtime rt = Runtime.getRuntime();
    final long mem = rt.totalMemory() - rt.freeMemory();
    return formatSize(mem);
  }

  /**
   * Formats a number according to the binary size orders (KB, MB, ...).
   * @param size value to be formatted
   * @return formatted size value
   */
  public static String formatSize(final long size) {
    if(size > (1L << 35)) return ((size + (1L << 29)) >> 30) + " GB";
    if(size > (1L << 25)) return ((size + (1L << 19)) >> 20) + " MB";
    if(size > (1L << 15)) return ((size + (1L <<  9)) >> 10) + " KB";
    return size + " Bytes";
  }

  /**
   * Formats a file size according to the binary size orders (KB, MB, ...).
   * @param size file size
   * @param det detailed suffix
   * @return formatted size value
   */
  public static String formatSize(final long size, final boolean det) {
    if(size > (1 << 20)) return ((size + (1 << 19)) >> 20) + " MB";
    if(size > (1 << 10)) return ((size + (1 <<  9)) >> 10) + " KB";
    return size + (det ? " Bytes" : " B");
  }

  /**
   * Sleeps the specified number of milliseconds.
   * @param ms time in milliseconds to wait
   */
  public static void sleep(final int ms) {
    try {
      Thread.sleep(ms);
    } catch(final InterruptedException ex) {
      // should never occur..
      ex.printStackTrace();
    }
  }

  /**
   * Perform some garbage collection.
   * GC behavior in Java is a pretty complex task. Still, garbage collection
   * can be forced by calling it several times.
   * @param n number of times to execute garbage collection
   */
  public static void gc(final int n) {
    for(int i = 0; i < n; i++) System.gc();
  }
}
